package com.leyou.order.service;

import com.leyou.common.enums.ExceptionEnum;
import com.leyou.common.exception.LyException;
import com.leyou.common.threadlocals.UserHolder;
import com.leyou.common.utils.BeanHelper;
import com.leyou.common.utils.IdWorker;
import com.leyou.dto.pojo.SkuDTO;
import com.leyou.item.client.ItemClient;
import com.leyou.order.dto.CartDTO;
import com.leyou.order.dto.OrderDTO;
import com.leyou.order.enums.OrderStatusEnum;
import com.leyou.order.mapper.OrderDetailMapper;
import com.leyou.order.mapper.OrderLogisticsMapper;
import com.leyou.order.mapper.OrderMapper;
import com.leyou.order.pojo.Order;
import com.leyou.order.pojo.OrderDetail;
import com.leyou.order.pojo.OrderLogistics;
import com.leyou.order.vo.OrderDetailVO;
import com.leyou.order.vo.OrderLogisticsVO;
import com.leyou.order.vo.OrderVO;
import com.leyou.user.client.UserClient;
import com.leyou.user.dto.AddressDTO;
import io.seata.spring.annotation.GlobalTransactional;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
public class OrderService {
    @Autowired
    private OrderMapper orderMapper;
    @Autowired
    private OrderDetailMapper orderDetailMapper;
    @Autowired
    private OrderLogisticsMapper orderLogisticsMapper;
    @Autowired
    private ItemClient itemClient;
    @Autowired
    private UserClient userClient;
    @Autowired
    private IdWorker idWorker;


    @GlobalTransactional
    @Transactional(rollbackFor = Exception.class)
    public Long createOrder(OrderDTO orderDTO) {
        // 1. 创建订单对象设置属性值
        Order order = new Order();
        // 分布式id
        Long orderId = idWorker.nextId();
        order.setOrderId(orderId);
        // 邮费
        order.setPostFee(0L);
        //实际支付 = 总金额 - 活动金额 ； 这里为了测试我们写个1分
        order.setActualFee(1L);
        // 支付类型
        order.setPaymentType(1);
        // 拦截器传递过来的用户id
        order.setUserId(UserHolder.getUser().getId());
        // 订单的状态
        order.setStatus(OrderStatusEnum.INIT.value());
        // 发票类型，0无发票，1普通发票，2电子发票，3增值税发票
        order.setInvoiceType(0);
        // 订单来源，1：app  2：pc  3：微信
        order.setSourceType(2);

        // 得到购物车的信息
        List<CartDTO> carts = orderDTO.getCarts();
        // 把集合转为map，方便根据id查找数量
        Map<Long, Integer> cartMap = carts.stream().collect(Collectors.toMap(CartDTO::getSkuId, CartDTO::getNum));
        // 得到skuId
        List<Long> skuIdList = carts.stream().map(CartDTO::getSkuId).collect(Collectors.toList());
        // 通过购物车信息中的skuId获取sku集合
        List<SkuDTO> skuDTOList = itemClient.querySkuByIds(skuIdList);
        // 计算总金额
        long totalFee = skuDTOList.stream()
                .mapToLong(skuDTO -> skuDTO.getPrice() * cartMap.get(skuDTO.getId())) //
                .sum();
        // 设置订单总金额
        order.setTotalFee(totalFee);
        // 2. 保存数据到订单表
        int count = orderMapper.insertSelective(order);
        if (count != 1) {
            throw new LyException(ExceptionEnum.INSERT_OPERATION_FAIL);
        }

        // 3. 保存数据到订单详情表
        // 因为订单详情可以有多个，所以创建一个集合用于保存订单中的订单详情数据
        List<OrderDetail> orderDetailList = new ArrayList<>();
        // 遍历sku，把sku数据转为订单详情数据
        skuDTOList.forEach(skuDTO -> {
            OrderDetail orderDetail = BeanHelper.copyProperties(skuDTO, OrderDetail.class);
            // 设置特有属性
            orderDetail.setId(idWorker.nextId());
            orderDetail.setOrderId(orderId);
            // skuId
            orderDetail.setSkuId(skuDTO.getId());
            // 从cartMap中根据skuId获取购买的数量
            orderDetail.setNum(cartMap.get(skuDTO.getId()));
            // 获取一张图片
            orderDetail.setImage(StringUtils.substringBefore(skuDTO.getImages(), ","));
            orderDetail.setCreateTime(new Date());
            orderDetail.setUpdateTime(new Date());
            orderDetailList.add(orderDetail);
        });
        // 保存数据
        count = orderDetailMapper.insertList(orderDetailList);
        if (count != 1) {
            throw new LyException(ExceptionEnum.INSERT_OPERATION_FAIL);
        }

        // 4. 保存数据到物流信息表
        // 设置物流信息
        AddressDTO addressDTO = userClient.queryAddressById(UserHolder.getUser().getId(), orderDTO.getAddressId());
        // 将dto转为物流对象
        OrderLogistics orderLogistics = BeanHelper.copyProperties(addressDTO, OrderLogistics.class);
        // 设置订单id
        orderLogistics.setOrderId(orderId);
        // 保存数据
        count = orderLogisticsMapper.insertSelective(orderLogistics);
        if (count != 1) {
            throw new LyException(ExceptionEnum.INSERT_OPERATION_FAIL);
        }

        // 5. 减少库存量
        itemClient.minusStock(cartMap);

        // TODO：在这里模拟一个异常，测试spring事务能否回滚全部数据
        // int i = 1 / 0;

        // TODO：在这里模拟一个异常，测试 @GlobalTransactional 事务能否回滚全部数据
        int i = 1 / 0;

        // 6. TODO：从redis中删除购物车数据

        // 7. 返回订单编号
        return orderId;
    }

    public OrderVO queryOrderById(Long id) {
        // 查询订单
        Order order = orderMapper.selectByPrimaryKey(id);
        if (order == null) {
            // 订单不存在
            throw new LyException(ExceptionEnum.ORDER_NOT_FOUND);
        }
        // 判断是否当前用户在查询订单，防止别人知道你的订单用来查询
        Long userId = UserHolder.getUser().getId();
        if (!userId.equals(order.getUserId())) {
            throw new LyException(ExceptionEnum.ORDER_NOT_FOUND);
        }

        // 查询订单详情
        OrderDetail orderDetail = new OrderDetail();
        // 根据订单id查询
        orderDetail.setOrderId(order.getOrderId());
        List<OrderDetail> orderDetailList = orderDetailMapper.select(orderDetail);
        if (CollectionUtils.isEmpty(orderDetailList)) {
            throw new LyException(ExceptionEnum.ORDER_NOT_FOUND);
        }

        // 根据订单id查询物流
        OrderLogistics orderLogistics = orderLogisticsMapper.selectByPrimaryKey(id);
        if (orderLogistics == null) {
            throw new LyException(ExceptionEnum.ORDER_NOT_FOUND);
        }

        // 封装数据
        OrderVO orderVO = BeanHelper.copyProperties(order, OrderVO.class);
        orderVO.setDetailList(BeanHelper.copyWithCollection(orderDetailList, OrderDetailVO.class));
        orderVO.setLogistics(BeanHelper.copyProperties(orderLogistics, OrderLogisticsVO.class));

        // 返回数据
        return orderVO;
    }
}